/*
 * Copyright (c) 2007 The Chai Team
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

package com.google.projects.chai.util;

import com.google.projects.chai.data.HibernateUtil;
import com.google.projects.chai.data.User;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.Properties;
import java.util.Random;
import org.hibernate.ObjectNotFoundException;
import org.hibernate.Session;

/**
 * Home of various utility methods.
 * @author dap
 */
public class Util {
        private static MessageDigest digest;
        private static Random random;
        
        static {
                try {
                        digest = MessageDigest.getInstance("MD5");
                        random = new Random();
                } catch (NoSuchAlgorithmException ee) {
                        throw new ExceptionInInitializerError(ee);
                }
        }
        
        /**
         * Given a string whicRandom rand = new Random();
                byte[] bytes = new byte[Config.getCurrent().getPasswordHashLength()];
                rand.nextBytes(bytes);
                String confirmationHash = new String(bytes);h is a user's query against some column in the
         * database, return the String one could reasonably use to look in our
         * database for it. Basically, we replace spaces with wildcards and
         * surround the string with wildcards.
         *
         * @param input a string
         * @return the input string with spaces replaced with the database wild-
         *      card character, and wildcards on either end.
         */
        public static String makeSearchable(String input) {
                return ('%' + input.replace(' ', '%') + '%');
        }
        
        /**
         * Computes the hash of someone's password, used either when a password
         * is being set or for verification. We only store the hashed version in
         * the database. When a user tries to log in with password 'input', we 
         * compare hash(input) to what is stored in the database.
         * @param input a plaintext password
         * @return the hashed version of someone's password.
         */
        public static String hashPassword(String input) {
                String salted = input + Config.getCurrent().getPasswordSalt();
                byte[] bytes = salted.getBytes();
                return (new BigInteger(1, bytes).toString(16));
        }

        /**
         * Generates a new hash suitable for the Confirmation string for a new
         * User or email address.
         * @return a random string of the appropriate length for a confirmation
         *      hash
         */
        public static String generateConfirmationHash() {
                int length = Config.getCurrent().getConfirmationHashLength();
                byte[] bytes = new byte[length];
                random.nextBytes(bytes);
                return (new BigInteger(1, bytes).toString(16));
        }
        
        /**
         * Uses the default emailer to send the given email to the specified
         * address. The subject and body arguments are assumed to be entries in
         * the EmailTemplate database table. Replaces placeholders in the 
         * template with their values from the 'params' map.
         * <p>
         * Because this method accesses the database, it begins and commits a
         * transaction. You should not assume anything about the state of the
         * current Hibernate session after calling this method.
         *
         * @param toAddress the address to which to send the email
         * @param messageId the ID of this message in the EmailTemplate table.
         * @param params a mapping from fields in the email to values to be
         *      inserted.
         */
        public static void sendEmail(String toAddress, String messageId,
            Map<String, String> params) {
                if (!Config.getCurrent().getSendEmail())
                        return;
                
                InputStream props = Util.class.getResourceAsStream(
                    "/emails/" + messageId + ".properties");
                /* Not finding the email is a programmer error. */
                assert (props != null);
                Properties mail = new Properties();
                try {
                        mail.load(props);
                } catch (IOException ex) {
                        /*
                         * This is an unlikely system error. We're probably
                         * screwed at this point. We'll propagate that we
                         * failed and probably report it to the user in some
                         * generic way, logging the exception for later analysis.
                         */
                        throw new RuntimeException(ex);
                }
                
                String subject = mail.getProperty("Subject");
                String body = mail.getProperty("Body");
                
                for (String key : params.keySet()) {
                        String skey = "%{" + key + "}";
                        String val = params.get(key);
                        subject = subject.replace(skey, val);
                        body = body.replace(skey, val);
                }
                
                Config.getCurrent().getMailer().sendEmail(
                    new EmailMessage(toAddress, subject, body));
        }
        
        /**
         * @param uid a user's unique identifier
         * @return the user corresponding to that identifier, or null if none
         *      exists
         */
        public static User getUserForIdentifier(int uid) {
                User user = new User();
                Session dbsession = HibernateUtil.getCurrentSession();
                dbsession.beginTransaction();
                try {
                        dbsession.load(user, uid);
                } catch (ObjectNotFoundException e) {
                        dbsession.getTransaction().rollback();
                        return (null);
                }
                dbsession.getTransaction().commit();
                return (user);
        }
}
